package org.unicamp.gesture.ai;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

public class ImageCheck {
	
	public static boolean checkSignature(Bitmap signature) {
		for (Bitmap bmp : getSavedSignatures()) {
			double ssim = getSSIM(bmp, signature);
			double hist = getHistogramCompare(bmp, signature);
			
			System.out.println("SSIM: " + ssim);
			System.out.println("Hist: " + hist);
			
			if(hist > 0.95)
				return true;
		}
		
		return false;
	}

	private static List<Bitmap> getSavedSignatures() {
		List<Bitmap> lista = new ArrayList<Bitmap>();
		String path = Environment.getExternalStorageDirectory().toString();
		path = path + "/gsapp/";
		File folder = new File(path);
		int i = 0;
		File imageFile = new File(folder, i + ".png");
		while (imageFile.exists()) {
			FileInputStream fi;
			try {
				fi = new FileInputStream(imageFile);
				Bitmap bmp = BitmapFactory.decodeStream(fi);
				if (bmp != null) {
					lista.add(bmp);
				}
				fi.close();
				i++;
				imageFile = new File(folder, i + ".png");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return lista;
	}
	
	private static double getSSIM(Bitmap bmp1, Bitmap bmp2){
		int height = bmp1.getHeight();
		int width = bmp1.getWidth();
		int[] colors1 = new int[height * width];
		int[] colors2 = new int[height * width]; 
		bmp1.getPixels(colors1, 0, width, 1, 1, width -1, height -1);
		bmp2.getPixels(colors2, 0, width, 1, 1, width -1, height -1);
		
		//Calcula medias
		double avg1 = 0, avg2 = 0;
		
		for (int i : colors1) {
			avg1 += i;
		}
		avg1 /= colors1.length;
		
		for (int i : colors2) {
			avg2 += i;
		}
		avg2 /= colors2.length;
		
		//Calcula variancias
		double var1 =0, var2 = 0;
		
		for (int i : colors1) {
			var1 += Math.pow(i - avg1, 2);
		}
		var1 /= colors1.length;
		
		for (int i : colors1) {
			var2 += Math.pow(i - avg2, 2);
		}
		var2 /= colors2.length;
		
		//Calcula covariancia
		double cov = 0;
		
		for (int i  = 0; i < colors1.length; i ++) {
			cov += Math.abs((colors1[i] - avg1)) * Math.abs((colors2[i] - avg2));
		}
		cov /= colors1.length;
		
		double L = 2 ^ 32;
		double c1 = Math.pow(2, 0.01 * L -1) ;
		double c2 = Math.pow(2, 0.03 * L - 1);
		
		double ssim = (2 * avg1 * avg2) + c1;
		ssim *= (2 * cov) + c2;
		ssim /= ((avg1 * avg1) + (avg2 * avg2) + c1) * ((var1 * var1) + (var2 * var2) + c2);
		
		
		return ssim;
	}
	
	private static double getHistogramCompare(Bitmap bmp1, Bitmap bmp2){
		int height = bmp1.getHeight();
		int width = bmp1.getWidth();
		int[] colors1 = new int[height * width];
		int[] colors2 = new int[height * width]; 
		bmp1.getPixels(colors1, 0, width, 1, 1, width -1, height -1);
		bmp2.getPixels(colors2, 0, width, 1, 1, width -1, height -1);
		
		//Calcula medias
		int hist1[] = new int[height];
		int hist2[] = new int[height];
		
		for (int i  = 0; i < height; i ++) {
			int cV = 0;
			for (int j  = 0; j < width; j ++) {
				cV += (colors1[(i * width) + j] != 0? 1 : 0);
			}
			hist1[i] = cV;
		}
		
		for (int i  = 0; i < height; i ++) {
			int cV = 0;
			for (int j  = 0; j < width; j ++) {
				cV += (colors2[(i * width) + j] != 0? 1 : 0);
			}
			hist2[i] = cV;
		}
		return getHistogramCorrelation(hist1, hist2);
		
	}
	
	private static double getHistogramCorrelation(int hist1[], int hist2[]){
		
		//Calcula medias
		double avg1 = 0, avg2 = 0;
		
		for (int i : hist1) {
			avg1 += i;
		}
		avg1 /= hist1.length;
		
		for (int i : hist2) {
			avg2 += i;
		}
		avg2 /= hist2.length;
		
		double var1 =0, var2 = 0;
		
		for (int i : hist1) {
			var1 += Math.pow(i - avg1, 2);
		}
		
		for (int i : hist2) {
			var2 += Math.pow(i - avg2, 2);
		}
		
		double cov = 0;
		
		for (int i  = 0; i < hist1.length; i ++) {
			cov += Math.abs((hist1[i] - avg1)) * Math.abs((hist2[i] - avg2));
		}
		
		double d = cov / Math.sqrt(var1 * var2);
		return d;
		
	}


}
